package org.loong.crypto.extension.operator.jce;

import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.security.NoSuchAlgorithmException;

import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.operator.DigestCalculator;
import org.bouncycastle.operator.DigestCalculatorProvider;
import org.bouncycastle.operator.OperatorCreationException;
import org.loong.crypto.core.algorithm.MessageDigestAlgorithm;
import org.loong.crypto.service.CryptoService;

public class JceDigestCalculatorProviderBuilder {

    private CryptoService cryptoService;

    public JceDigestCalculatorProviderBuilder(CryptoService cryptoService) {
        this.cryptoService = cryptoService;
    }

    /**
     * Builder an digest calculator provider.
     * 
     * @return {@link DigestCalculatorProvider}
     * @throws OperatorCreationException {@link OperatorCreationException}
     */
    public DigestCalculatorProvider build() throws OperatorCreationException {
        return new DigestCalculatorProvider() {

            public DigestCalculator get(final AlgorithmIdentifier algorithm) throws OperatorCreationException {

                final ByteArrayOutputStream stream = new ByteArrayOutputStream();

                final MessageDigestAlgorithm digestAlgorithm;
                try {
                    digestAlgorithm = MessageDigestAlgorithm.findByAlgorithmId(algorithm);
                } catch (NoSuchAlgorithmException e) {
                    throw new OperatorCreationException("No such algorethm [" + algorithm.getAlgorithm().getId() + "] in digest algorithms.", e);
                }

                return new DigestCalculator() {

                    public AlgorithmIdentifier getAlgorithmIdentifier() {
                        return algorithm;
                    }

                    public OutputStream getOutputStream() {
                        return stream;
                    }

                    public byte[] getDigest() {
                        final byte[] data = stream.toByteArray();
                        return cryptoService.digest(digestAlgorithm, data);
                    }
                };
            }
        };
    }
}
